package com.bwie.auth.service.impl;

import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.dysmsapi20170525.models.SendSmsResponseBody;
import com.bwie.auth.exception.ServiceException;
import com.bwie.auth.remote.UserRemoteService;
import com.bwie.auth.service.AuthService;
import com.bwie.auth.utils.TelSmsUtils;
import com.bwie.common.constants.JwtConstants;
import com.bwie.common.constants.TokenConstants;
import com.bwie.common.domain.Log;
import com.bwie.common.domain.User;
import com.bwie.common.domain.request.UserReq;
import com.bwie.common.domain.response.UserRes;
import com.bwie.common.result.Result;
import com.bwie.common.utils.JwtUtils;
import com.bwie.common.utils.StringUtils;
import lombok.extern.log4j.Log4j2;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.HashMap;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;

@Service
@Log4j2
public class AuthServiceImpl implements AuthService {
    @Autowired
    private UserRemoteService userRemoteService;
    @Autowired
    private HttpServletRequest request;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private TelSmsUtils telSmsUtils;
    @Autowired
    private RabbitTemplate rabbitTemplate;


    @Override
    public void getCode(String phone) {
        if (StringUtils.isBlank(phone)){
            throw new ServiceException("手机号不能为空");
        }
        if (!validate(phone)){
            throw new ServiceException("手机号格式不正确");
        }

//        // 构造 Redis 中存储验证码发送时间的键
//        String sentKey = "verification_sent_at:" + phone;
//
//        // 检查验证码是否在 1 分钟内已经发送过
//        Long lastSentTime = redisTemplate.opsForValue().get(sentKey);
//        if (lastSentTime != null && (System.currentTimeMillis() - lastSentTime) < 60000) {
//            throw new ServiceException("验证码发送太频繁，请稍后再试");
//        }

        Result<User> user = userRemoteService.findUser(phone);
        User data = user.getData();
        if (data==null){
            throw new ServiceException("用户不存在，去注册");
        }
        String code = RandomUtil.randomNumbers(4);
        redisTemplate.opsForValue().set(phone,code,15, TimeUnit.MINUTES);
//        // 记录验证码发送时间到 Redis，设置 1 分钟过期
//        redisTemplate.opsForValue().set(sentKey, System.currentTimeMillis(), 1, TimeUnit.MINUTES);

        // 调用 短信工具类  发短信  SendSmsResponseBody一个对象 拿里面的code判断
        SendSmsResponseBody sendSmsResponseBody = telSmsUtils.sendSms(phone, new HashMap<String, String>() {{
            put("code", code);
        }});
        //验证码使用短信发送到用户手机中，短信发送失败进行重新发送短信，最多重试3次
        int count=0;
        int retryCount=0;
        //如果 验证码发送失败   进行判断
        if (!"ok".equalsIgnoreCase(sendSmsResponseBody.getCode())){
            //当 0次 < 3次  发短信  记次数
            while (count<retryCount){
                SendSmsResponseBody res = telSmsUtils.sendSms(phone, new HashMap<String, String>() {{
                    put("code", code);
                }});
                if ("ok".equalsIgnoreCase(res.getCode())){
                    break;
                }
                count++;
            }
            if (count==3){
                throw new ServiceException("已经重试3次了，请稍后再试");
            }
        }

    }

    @Override
    public UserRes phoneLogin(UserReq userReq) {
        if (StringUtils.isBlank(userReq.getPhone())){
            throw new ServiceException("手机号不能为空");
        }
        if (StringUtils.isBlank(userReq.getCode())){
            throw new ServiceException("验证码不能为空");
        }
        if (!validate(userReq.getPhone())){
            throw new RuntimeException("手机号格式不正确");
        }
        Result<User> user = userRemoteService.findUser(userReq.getPhone());
        User data = user.getData();
        if (data==null){
            throw  new ServiceException("用户不存在，去注册");
        }
        if (!redisTemplate.hasKey(userReq.getPhone())){
            throw new ServiceException("验证码过期");
        }
        String cacheCode = redisTemplate.opsForValue().get(userReq.getPhone());
        if (!userReq.getCode().equals(cacheCode)){
            throw new ServiceException("验证码错误");
        }
        Log log = new Log();
        log.setLogName(userReq.getUserName());//想记录 当前登录人
        log.setLogTime(new Date());
        //异步发消息
        rabbitTemplate.convertAndSend("success_queue",log,message -> {
            //设置唯一标识
            message.getMessageProperties().setMessageId(UUID.randomUUID().toString());
            return message;
        });
        //创建map集合
        HashMap<String, Object> map = new HashMap<>();
        //生成随机不重复的字符串 生成key
        String userKey = UUID.randomUUID().toString().replaceAll("-", "");
        //存入信息
        map.put(JwtConstants.USER_KEY,userKey);
        //生成token
        String token = JwtUtils.createToken(map);
        //存缓存  把对象转化为JSON字符串  过期时间15min
        redisTemplate.opsForValue().set(TokenConstants.LOGIN_TOKEN_KEY+userKey, JSONObject.toJSONString(data),15,TimeUnit.MINUTES);
        UserRes userRes = new UserRes();
        userRes.setToken(token);
        userRes.setTime(TokenConstants.TOKEN_EXPIRATION_TIME_STR);
        return userRes;
    }

    @Override
    public User userInfo() {
        //获取请求头中的 token
        String token = request.getHeader(TokenConstants.TOKEN);
        //反向解析出userKey
        String userKey = JwtUtils.getUserKey(token);
        //获取用户信息
        String userJSONStr = redisTemplate.opsForValue().get(TokenConstants.LOGIN_TOKEN_KEY + userKey);
        return JSONObject.parseObject(userJSONStr,User.class);
    }

    @Override
    public void logout() {
        //获取请求头中的 token
        String token = request.getHeader(TokenConstants.TOKEN);
        //反向解析出userKey
        String userKey = JwtUtils.getUserKey(token);
        //删除用户信息
        redisTemplate.delete(TokenConstants.LOGIN_TOKEN_KEY + userKey);
    }

    public boolean validate(String phone){
        return Pattern.matches("^(?:(?:\\+|00)86)?1(?:(?:3[\\d])|(?:4[5-79])|(?:5[0-35-9])|(?:6[5-7])|(?:7[0-8])|(?:8[\\d])|(?:9[189]))\\d{8}$",phone);
    }
}
